// common.c
// Joseph Craig, Rebecca Rush, Steven Andryzcik
// Version 6 - 12/08/2011

#include <string.h>

#include "common.h"
#include "mpx_supt.h"

// get_string_strip_endline
// Parameters: string, length of string
// Return: error_code
// Functions called: sys_req
// Removes the end of line character from the end of a string
int get_string_strip_endline(char *buffer, int length) {
	int error_code;
	int i;
	
	if (
		ERR_SUP_RDFAIL != (
			error_code = sys_req(
				READ,
				TERMINAL,
				buffer,
				&length)
		)
	) {
		for (i = 0; i < length && buffer[i] != '\0'; i++);
		if (buffer[i - 1] == '\n') {
			buffer[i - 1] = '\0';
		}
	}
	
	return error_code;
}

// is_leap_year
// Parameters: year
// Return: 1 if true or 0 if false
// Functions called: none
// Determines if it is leap year
int is_leap_year(long year) {
	return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
}

// numberp
// Parameters: string, length of string
// Return: True or False
// Functions called: none
// Determines if a string is a number.
int numberp(char *string, int length) {
	char current;
	int i;
	int to_return = TRUE;
	
	for (
		i = 0,
		current = string[0];
		to_return == TRUE && i < length && current != '\0';
		i++,
		current = string[i]
	) {
		if (
			(current < '0' || current > '9') &&
			(i != 0 || (current != '+' && current != '-'))
		) {
			to_return = FALSE;
		}
	}
	
	return to_return;
    }

// print
// Parameters: string to print, true or false
// Return: OK
// Functions called: sys_req, system	
// Takes care of the calls to sys_req(WRITE, TERMINAL, ...)
int print(char *to_print, int flush) {
	static char buffer[PRINT_BUFFER]  = "";
	static int length = 0;
	static int lines  = 0;
	static int x      = 0;
	
	static char where[] = {1, 23};
	
	static const int coord_length = 2;
	
	int
		breaks  = 0,
		current = x,
		i       = 0,
		total   = 0;
	
	/* Count how many lines and characters there are in the passed string.
	 */
	while (to_print[i] != '\0') {
		total++;
		
		if (to_print[i] == '\t') {
			current += TAB - current % TAB;
			
			if (current >= TERMINAL_WIDTH) {
				breaks++;
				current = 0;
			}
		} else if (to_print[i] == '\r' || to_print[i] == '\n') {
			breaks++;
			current = 0;
		} else if (current == TERMINAL_WIDTH) {
			breaks++;
			current = 1;
		} else {
			current++;
		}
		
		i++;
	}
	
	/* If adding the current string would make the buffer too long (in lines or
	 * characters), flush the buffer and start over.
	 */
	if (
		(lines + breaks >= MAX_LINES || length + total >= PRINT_BUFFER - 1) &&
		length > 0
	) {
		sys_req(WRITE, TERMINAL, buffer, &length);
		length = lines = x = 0;
		
		system("pause");
		where[1] = wherey() - 2;
		sys_req(GOTOXY, TERMINAL, where, &coord_length);
	}
	
	/* While there are too many characters or lines to fit in the buffer, pass
	 * everything straight to sys_req so only that which will fit is buffered.
	 */
	while (lines + breaks > MAX_LINES || length + total >= PRINT_BUFFER - 1) {
		int local_breaks = 0;
		i = current = 0;
		
		while (i < PRINT_BUFFER - 1 && local_breaks < MAX_LINES) {
			if (to_print[i] == '\t') {
				current += TAB - current % TAB;
				
				if (current >= TERMINAL_WIDTH) {
					local_breaks++;
					breaks--;
					current = 0;
				}
			} else if (to_print[i] == '\r' || to_print[i] == '\n') {
				local_breaks++;
				breaks--;
				current = 0;
			} else if (current == TERMINAL_WIDTH) {
				local_breaks++;
				breaks--;
				current = 1;
			} else {
				current++;
			}
			
			i++;
		}
		
		sys_req(WRITE, TERMINAL, to_print, &i);
		system("pause");
		where[1] = wherey() - 2;
		sys_req(GOTOXY, TERMINAL, where, &coord_length);
		
		to_print += i;
		total -= i;
	}
	
	/* Copy all remaining characters to the buffer, incrementing the appropriate
	 * counts.
	 */
	i = 0;
	while (to_print[i] != '\0') {
		if (to_print[i] == '\t') {
			x += TAB - x % TAB;
			
			if (x >= TERMINAL_WIDTH) {
				lines++;
				x = 0;
			}
		} else if (to_print[i] == '\r' || to_print[i] == '\n') {
			lines++;
			x = 0;
		} else if (x == TERMINAL_WIDTH) {
			lines++;
			x = 1;
		} else {
			x++;
		}
		buffer[length++] = to_print[i];
		i++;
	}
	 
	buffer[length] = '\0';
	/* 
	 * If flush is equal true, print everything from buffer.
	 */
	if (flush == TRUE) {
		sys_req(WRITE, TERMINAL, buffer, &length);
		length = lines = x = 0;
	}
	
	return OK;
}

// print_file
// Parameters: filename
// Return: to_return
// Functions called: fopen, fseek, ftell, rewind,
// sys_alloc_mem, fgets, print, close
int print_file(char *filename) {
	FILE *file = NULL;
	int
		characters_read = 0,
		file_length,
		to_return = NOT_OK;
	unsigned char *file_contents = NULL;
	
	/* Attempt to open the file.
	 */
	if ((file = fopen(filename, "rb")) != NULL) {
		to_return = ERR_GEN_OUTOFMEMORY;
		
		/* Determine the number of characters in the file.
		 */
		fseek(file, 0, SEEK_END);
		file_length = ftell(file) + 1;
		rewind(file);
		
		/* Attempt to allocate enough space for the file's contents.
		 */
		file_contents = sys_alloc_mem(file_length + 1);
		if (file_contents != NULL) {
			to_return = OK;
			
			/* Read all the characters from the file into the buffer, then add
			 * an extra newline at the end.
			 */
			while (
				fgets(
					file_contents + characters_read,
					file_length + 1,
					file
				)
			) {
				characters_read = strlen(file_contents);
			}
			
			file_contents[file_length]     = '\n';
			file_contents[file_length + 1] = '\0';
			
			/* Write the buffer to the terminal.
			 */
			print(file_contents, TRUE);
			
			/* Free the file contents memory.
			 */
			sys_free_mem(file_contents);
		}
		
		/* Close the file pointer.
		 */
		fclose(file);
	}
	
	/* Return whether the function succeeded in opening the file.
	 */
	return to_return;
}
